# coding=utf-8
import pathlib
import pandas as pd
from functools import partial
from gm.api import *
from quant import strategy, trader
from quant.data import juejin, jisilu
from quant.vlogger import VLogger
from datetime import datetime, time
import click

# mode = MODE_LIVE
mode = MODE_BACKTEST
start_date = '2022-04-07'
end_date = '2022-04-21'
confirm = True


def get_conbond_data(instruments: pd.DataFrame, bars: pd.DataFrame, context,
                     _):
    dt = datetime.combine(context.now.date(), time(0, 0, 0))
    data = bars.loc[pd.IndexSlice[dt:dt, :]].join(
        instruments[[
            'bond_type', 'symbol', 'maturity_date', 'record_date',
            'stop_trading_date', 'de_listed_date'
        ]])
    return data


def jsl(context, bar_dict):
    _, bars = jisilu.refresh_now(pathlib.Path('./jisilu'))
    bars = bars.reset_index()
    bars['order_book_id'] = bars.apply(
        lambda row: 'SHSE.%s' % row.order_book_id
        if row.market_cd == 'shmb' else 'SZSE.%s' % row.order_book_id,
        axis=1)
    bars.set_index(['datetime', 'order_book_id'], inplace=True)
    return bars


def conbond_data_fn(m):
    if m == MODE_BACKTEST:
        instruments, bars = juejin.refresh_conbond(start_date, end_date, '1d',
                                                   pathlib.Path('./juejin'),
                                                   pathlib.Path('./jisilu'))
        return partial(get_conbond_data, instruments, bars)
    else:
        return jsl


def init(context):
    VLogger.info('init')
    context.trader = trader.JuejinTrader(mode)
    context.strategy = strategy.ConbondRotateStrategy(
        'multi_factors_rank', {
            'threshold': 130,
            'rebalance': '日',
            'days_to_maturity': 10,
            'days_to_stop_trading': 10,
            'weight_price': 0.2,
            'weight_cpr': 0.4,
            'weight_remaining_size': 0.4,
            'top': 20,
        }, context.trader,
        conbond_data_fn(mode))
    if mode == MODE_BACKTEST:
        VLogger.v = 1
        context.strategy.init(context)
    else:
        VLogger.v = 1
        context.strategy.rebalance(context)


def on_order_status(context, order):
    dt = context.now
    if order.status == OrderStatus_Filled:
        VLogger.info(
            '{}: {} order_book_id: {}, price: {}, volume: {}, value: {}'.
                format(dt, '买入' if order.side == OrderSide_Buy else '卖出',
                       order.symbol, order.price, order.volume,
                       order.value))
    elif order.status == OrderStatus_Rejected:
        if order.volume == 0:
            pass
        else:
            VLogger.error(
                '{}: status: {}, target: {}, error: {}'.format(
                    dt, order.status, order.symbol,
                    order.ord_rej_reason_detail))
            if confirm:
                VLogger.error(order)
                VLogger.error(context.account().position(order.symbol,
                                                         PositionSide_Long))
                click.confirm('Error')
    else:
        # VLogger.warning('{}: {}'.format(dt, order))
        pass


# 查看最终的回测结果
def on_backtest_finished(context, indicator):
    VLogger.info(indicator)


if __name__ == '__main__':
    '''
        strategy_id策略ID, 由系统生成
        filename文件名, 请与本文件名保持一致
        mode运行模式, 实时模式:MODE_LIVE回测模式:MODE_BACKTEST
        token绑定计算机的ID, 可在系统设置-密钥管理中生成
        backtest_start_time回测开始时间
        backtest_end_time回测结束时间
        backtest_adjust股票复权方式, 不复权:ADJUST_NONE前复权:ADJUST_PREV后复权:ADJUST_POST
        backtest_initial_cash回测初始资金
        backtest_commission_ratio回测佣金比例
        backtest_slippage_ratio回测滑点比例
    '''
    import logging
    logging.getLogger().setLevel(logging.INFO)
    from easydict import EasyDict
    import json

    auth_file = pathlib.Path('~/.cache/quant/.auth.json').expanduser()
    cred = EasyDict(json.load(auth_file.open(mode='r')))
    VLogger.info('Running with server: %s' % cred.juejin.username)
    run(strategy_id='334af32d-a5a8-11ec-b6e4-2a16a8610fe9',
        filename='main.py',
        mode=mode,
        token=cred.juejin.password,
        backtest_start_time='%s 00:00:00' % start_date,
        backtest_end_time='%s 23:59:59' % end_date,
        backtest_adjust=ADJUST_PREV,
        backtest_initial_cash=1000000,
        backtest_commission_ratio=0.0001,
        backtest_slippage_ratio=0.0001,
        serv_addr=cred.juejin.username)
